{*

{*------------------------------------------------------------------------------
  @author  Norbert Dudek <norbertdudek@gmail.com>
  @version 1.01
  @comment
        Copyright (C) 2010  Norbert Dudek (norbertdudek@gmail.com)

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

-------------------------------------------------------------------------------}
unit FormMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ToolWin, ActnMan, ActnCtrls, ActnMenus, ActnList,
  Menus, Buttons, ComCtrls, JvExComCtrls, JvDateTimePicker, JvExStdCtrls,
  JvListBox, Mask, JvExMask, JvSpin, ExtCtrls, JvExControls,
  JvSegmentedLEDDisplay;

type
  TFrmMain = class(TForm)
    mmMain: TMainMenu;
    actlstMain: TActionList;
    actAdd: TAction;
    actRemove: TAction;
    actSave: TAction;
    actLoad: TAction;
    File1: TMenuItem;
    actNew: TAction;
    actNew1: TMenuItem;
    actSave1: TMenuItem;
    actLoad1: TMenuItem;
    Items1: TMenuItem;
    actAdd1: TMenuItem;
    actRemove1: TMenuItem;
    N1: TMenuItem;
    actClose: TAction;
    Close1: TMenuItem;
    actStart: TAction;
    actStop: TAction;
    btnStart: TBitBtn;
    btnAdd: TBitBtn;
    btnRemove: TBitBtn;
    btnStop: TBitBtn;
    btnClose: TBitBtn;
    lstTimes: TJvListBox;
    tmrMain: TTimer;
    labTimer: TJvSegmentedLEDDisplay;
    dtpTime: TJvDateTimePicker;
    N2: TMenuItem;
    actFile: TAction;
    actItems: TAction;
    lblAbout: TLabel;
    tmrAbout: TTimer;
    procedure actCloseExecute(Sender: TObject);
    procedure actAddExecute(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure actRemoveExecute(Sender: TObject);
    procedure actRemoveUpdate(Sender: TObject);
    procedure actSaveExecute(Sender: TObject);
    procedure actLoadExecute(Sender: TObject);
    procedure actNewExecute(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure lstTimesClick(Sender: TObject);
    procedure edtTimeChange(Sender: TObject);
    procedure actStartExecute(Sender: TObject);
    procedure actStopExecute(Sender: TObject);
    procedure actAddUpdate(Sender: TObject);
    procedure actStartUpdate(Sender: TObject);
    procedure actStopUpdate(Sender: TObject);
    procedure actNewUpdate(Sender: TObject);
    procedure actSaveUpdate(Sender: TObject);
    procedure actLoadUpdate(Sender: TObject);
    procedure tmrMainTimer(Sender: TObject);
    procedure actCloseUpdate(Sender: TObject);
    procedure lstTimesDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure lstTimesMeasureItem(Control: TWinControl; Index: Integer;
      var Height: Integer);
    procedure actFileExecute(Sender: TObject);
    procedure actItemsExecute(Sender: TObject);
    procedure tmrAboutTimer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure lblAboutClick(Sender: TObject);
  private
    { Private declarations }
    FModified: Boolean;
    FRemainingTime: Integer;
    FFadeText: TStringList;
    FFadeIndex: Integer;
    FFadeStep: Integer;
    function SaveToFile: Boolean;
    function CheckModified: Boolean;
    procedure SetRemainingTime(const Value: Integer);
  public
    { Public declarations }
    function SecToText(Value: Integer): string;

    property Modified: Boolean read FModified write FModified;
    property RemainingTime: Integer read FRemainingTime write SetRemainingTime;
  end;

var
  FrmMain: TFrmMain;

implementation
uses
  JvGnugettext, MMSystem, ShellAPI;

{$R *.dfm}

procedure TFrmMain.actAddExecute(Sender: TObject);
begin
  lstTimes.Items.AddObject('60', Pointer(60));
  lstTimes.ItemIndex := lstTimes.Items.Count -1;
  lstTimesClick(lstTimes);
  Modified := true;
end;

procedure TFrmMain.actAddUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := not tmrMain.Enabled;
end;

procedure TFrmMain.actCloseExecute(Sender: TObject);
begin
  Close;
end;

procedure TFrmMain.actCloseUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := not tmrMain.Enabled;
end;

procedure TFrmMain.actFileExecute(Sender: TObject);
begin
  {Nothing}
end;

procedure TFrmMain.actItemsExecute(Sender: TObject);
begin
  {Nothing}
end;

procedure TFrmMain.actLoadExecute(Sender: TObject);
var
  i: Integer;
begin
  if CheckModified then
    with TOpenDialog.Create(Self) do
    try
      DefaultExt := '.tick';
      Filter := _('Tick tick files (*.tick)|*tick|Any file|*.*');
      if Execute then
      try
        lstTimes.Items.LoadFromFile(FileName);
        for i := 0 to lstTimes.Items.Count -1 do
          lstTimes.Items.Objects[i] := Pointer(StrToInt(lstTimes.Items[i]));
        lstTimes.Repaint;
        Modified := false;
      except
        MessageDlg(Format(_('Can''not load the filename %s'), [FileName]), mtError, [mbOK], 0);
      end;
    finally
      Free;
    end;
end;

procedure TFrmMain.actLoadUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := not tmrMain.Enabled;
end;

procedure TFrmMain.actNewExecute(Sender: TObject);
begin
  if CheckModified then
  begin
    lstTimes.Items.Clear;
    Modified := False;
  end;
end;

procedure TFrmMain.actNewUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := not tmrMain.Enabled;
end;

procedure TFrmMain.actRemoveExecute(Sender: TObject);
begin
  lstTimes.Items.Delete(lstTimes.ItemIndex);
  Modified := true;
end;

procedure TFrmMain.actRemoveUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := (lstTimes.ItemIndex >= 0) and (not tmrMain.Enabled);
end;

procedure TFrmMain.actSaveExecute(Sender: TObject);
begin
  SaveToFile;
end;

procedure TFrmMain.actSaveUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := not tmrMain.Enabled;
end;

procedure TFrmMain.actStartExecute(Sender: TObject);
begin
  PlaySound('metronome', hInstance, SND_RESOURCE or SND_ASYNC or SND_LOOP);
  lstTimes.ItemIndex := 0;
  tmrMain.Enabled := true;

  RemainingTime := StrToInt(lstTimes.Items[0]);
end;

procedure TFrmMain.actStartUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := (not tmrMain.Enabled) and (lstTimes.Items.Count > 0);
  lstTimes.Enabled := (not tmrMain.Enabled);
  dtpTime.Enabled := (not tmrMain.Enabled);
end;

procedure TFrmMain.actStopExecute(Sender: TObject);
begin
  tmrMain.Enabled := false;
  labTimer.Text := '';
  PlaySound('stop', hInstance, SND_RESOURCE or SND_ASYNC);
  lstTimesClick(lstTimes);
end;

procedure TFrmMain.actStopUpdate(Sender: TObject);
begin
  (Sender as TAction).Enabled := tmrMain.Enabled;
end;

function TFrmMain.CheckModified: Boolean;
begin
  Result := not Modified;
  if Modified then
    case MessageDlg(_('Save changes?'), mtConfirmation, [mbYes, mbNo, mbCancel], 0) of
      mrCancel:
        result := False;
      mrYes:
        Result := SaveToFile;
      mrNo:
        result := True;
    end;
end;

procedure TFrmMain.edtTimeChange(Sender: TObject);
var
  H, M, S, SSec: Word;
begin
  DecodeTime(dtpTime.Time, H, M, S, SSec);
  if lstTimes.ItemIndex >= 0 then
  begin
    lstTimes.Items[lstTimes.ItemIndex] := IntToStr(M *60 +S);
    lstTimes.Items.Objects[lstTimes.ItemIndex] := Pointer(M *60 +S);
  end;
end;

procedure TFrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := (not tmrMain.Enabled) and CheckModified;
end;

procedure TFrmMain.FormCreate(Sender: TObject);
begin
  FFadeText := TStringList.Create;
  FFadeText.Text := lblAbout.Caption;
  FFadeStep := 0;
  FFadeIndex := 0;
  
  Modified := False;
  TranslateComponent(Self, '');
end;

procedure TFrmMain.FormDestroy(Sender: TObject);
begin
  FFadeText.Free;
end;

procedure TFrmMain.lblAboutClick(Sender: TObject);
begin
  ShellExecute(0, 'open', 'http://www.norbertdudek.pl', '', '', SW_SHOW);
end;

procedure TFrmMain.lstTimesClick(Sender: TObject);
begin
  if lstTimes.ItemIndex >= 0 then
    dtpTime.Time := EncodeTime(0, Integer(lstTimes.Items.Objects[lstTimes.ItemIndex]) div 60, Integer(lstTimes.Items.Objects[lstTimes.ItemIndex]) mod 60, 0)
  else
    dtpTime.Time := 0;
end;

procedure TFrmMain.lstTimesDrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  with (Control as TJvListBox), (Control as TJvListBox).Canvas do
  begin
    FillRect(Rect);
    DrawText(Handle, PAnsiChar(SecToText(Integer(Items.Objects[Index]))), -1, Rect, DT_RIGHT or DT_VCENTER )
  end;
end;

procedure TFrmMain.lstTimesMeasureItem(Control: TWinControl; Index: Integer;
  var Height: Integer);
var
  Rect: TRect;
begin
  with (Control as TJvListBox).Canvas do
  begin
    Font := (Control as TJvListBox).Font;
    Height := TextHeight((Control as TJvListBox).Items[Index]);
  end;
end;

function TFrmMain.SaveToFile: Boolean;
begin
  result := False;
  with TSaveDialog.Create(Self) do
  try
    DefaultExt := '.tick';
    Filter := _('Tick tick files (*.tick)|*tick|Any file|*.*');
    if Execute then
    try
      lstTimes.Items.SaveToFile(FileName);
      Modified := False;
      result := True;
    except
      MessageDlg(Format(_('Can''not save the filename %s'), [FileName]), mtError, [mbOK], 0);
    end;
  finally
    Free;
  end;
end;

function TFrmMain.SecToText(Value: Integer): string;
begin
  result := Format('%2d:%0.2d', [Value div 60, Value mod 60]);
end;

procedure TFrmMain.SetRemainingTime(const Value: Integer);
var
  Text: string;
begin
  FRemainingTime := Value;
  Text := SecToText(Value);
  while Length(Text) < 5 do
    Text := ' ' +Text;

  labTimer.Text := text;
end;

procedure TFrmMain.tmrAboutTimer(Sender: TObject);
var
  LRed: Integer;
begin
  if FFadeIndex +1 < FFadeText.Count then
    lblAbout.Caption := FFadeText[FFadeIndex] +#13#10 +FFadeText[FFadeIndex +1]
  else
    lblAbout.Caption := FFadeText[FFadeIndex];
  Inc(FFadeStep, 3);
  LRed := (abs(120 -FFadeStep) *2);

  if FFadeStep >= 240 then
  begin
    FFadeStep := 0;
    Inc(FFadeIndex, 2);
    if FFadeIndex >= FFadeText.Count then
      FFadeIndex := 0;
  end;

  lblAbout.Font.Color := RGB(LRed, LRed, LRed);
end;

procedure TFrmMain.tmrMainTimer(Sender: TObject);
begin
  RemainingTime := RemainingTime -1;
  if RemainingTime = 0 then
  begin
    if lstTimes.ItemIndex < lstTimes.Items.Count -1 then
    begin
      PlaySound('sound', hInstance, SND_RESOURCE or SND_SYNC);
      PlaySound('metronome', hInstance, SND_RESOURCE or SND_ASYNC or SND_LOOP);
      lstTimes.ItemIndex := lstTimes.ItemIndex +1;
      RemainingTime := StrToInt(lstTimes.Items[lstTimes.ItemIndex]);
    end
    else
      actStop.Execute;
  end;
end;

end.
